const service = require("../../service/user")
const jwt = require("jsonwebtoken")

const {
  Types: {
    ObjectId: { isValid }
  }
} = require("mongoose")

class User {
  constructor() {
    this.instance = null
  }
  static get Instance() {
    return this.instance || (this.instance = new User())
  }

  async getUsers(ctx) {
    let { pageNum = 10, page = 1, q = "" } = ctx.query
    pageNum = Math.max(pageNum - 0 || 10, 1)
    page = Math.max(page - 0, 1) - 1
    let skipNum = page * pageNum
    const users = await service.getUsers(pageNum, skipNum, q)
    ctx.rest(users)
  }

  async addUser(ctx) {
    ctx.verifyParams({
      username: { type: "string", required: true },
      password: { type: "string", required: true }
    })
    const user = ctx.request.body
    const _user = await service.addUser(user)
    if (!_user) return ctx.throw(404, "The user had already existed!")
    return ctx.rest(_user)
  }

  async getUserById(ctx) {
    const uid = ctx.params.uid
    if (!uid) return ctx.throw(404, "uid is missed")
    const { fields = "" } = ctx.query
    const user = await service.getUserById(uid, fields)
    if (!user) return ctx.throw(404, "The user is not existed")
    ctx.rest(user)
  }

  async updateUser(ctx) {
    const uid = ctx.params.uid
    if (!uid) return ctx.throw(404, "uid is missed")
    ctx.verifyParams({
      username: { type: "string", required: false },
      password: { type: "string", required: false },
      gender: { type: "string", required: false },
      age: { type: "number", required: false },
      headline: { type: "string", required: false },
      locations: { type: "array", itemType: "string", required: false },
      business: { type: "string", required: false },
      employments: { type: "array", itemType: "object", required: false },
      educations: { type: "array", itemType: "object", required: false },
      personal_profile: { type: "string", required: false }
    })
    const data = ctx.request.body
    const user = await service.updateUser(uid, data)
    if (!user) return ctx.throw(404, "The user is not existed")
    ctx.rest(user)
  }

  async deleteUser(ctx) {
    const uid = ctx.params.uid
    if (!uid) return ctx.throw(404, "uid is missed")
    const user = await service.delUserById(uid)
    if (!user) return ctx.throw(404, "The user is not existed")
    ctx.rest(user)
  }

  async login(ctx) {
    ctx.verifyParams({
      username: { type: "string", required: true },
      password: { type: "string", required: true }
    })
    const data = ctx.request.body
    const user = await service.getUserByModal(data)
    if (!user) return ctx.throw("The username or password is not correctly!")
    const { _id, username } = user
    const token = jwt.sign({ _id, username }, process.env.JWT_SECRET, {
      expiresIn: ctx.config.tokenExpiresIn || "60m"
    })
    ctx.rest(token)
  }

  async errTest412(ctx) {
    ctx.throw(412, "there is a logical error")
  }

  async errTest500(ctx) {
    a.b
  }

  async listFollowings(ctx) {
    const uid = ctx.params.uid
    if (!uid) return ctx.throw(404)
    const user = await service.listFollowings(uid)
    if (!user) return ctx.throw("the user is not existed!")
    ctx.rest(user.followings)
  }

  async follow(ctx) {
    const uid = ctx.state.user._id
    const fid = ctx.params.uid
    if (!isValid(fid)) return ctx.throw(404, "invalid id of users")
    if (!fid) return ctx.throw(404, 'can not get params of "fid" ')
    const res = await service.addFollowing(uid, fid)
    if (!res)
      return ctx.throw(
        404,
        "You had already followed this user or this user is not existed!"
      )
    ctx.rest(res)
  }

  async cancelFollow(ctx) {
    const uid = ctx.state.user._id
    const fid = ctx.params.uid
    if (!isValid(fid)) return ctx.throw(404, "invalid id of users")
    if (!fid) return ctx.throw(404, 'can not get params of "fid" ')
    const res = await service.cancelFollowing(uid, fid)
    if (!res)
      return ctx.throw(
        404,
        "You had never follow this user or this user is not existed!"
      )
    ctx.rest(res)
  }

  async listFans(ctx) {
    const uid = ctx.params.uid
    if (!isValid(uid)) return ctx.throw(404, "The user's id is illegal")
    const user = await service.listFans(uid)
    return ctx.rest(user)
  }
}

const I = User.Instance

module.exports = I
